package com.muyu.service.impl;

import com.muyu.api.exception.BusinessException;
import com.muyu.model.config.ReviewFileConfigDTO;
import com.muyu.model.entity.UserQuestionsEntity;
import com.muyu.service.CommonService;
import com.muyu.service.UserQuestionsService;
import com.muyu.util.Uploader;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.IOUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.zip.ZipOutputStream;

/**
 * @ClassName: CommonServiceImpl
 * @Author: Zirun.Xin
 * @Date: 2025/4/29 下午2:34
 * @Version: 1.0
 * @Description: 公共业务实现层
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CommonServiceImpl implements CommonService {

    /**
     * 问题反馈业务层
     */
    private final UserQuestionsService userQuestionsService;

    /**
     * 自定义文件存放地址配置对象
     */
    private final ReviewFileConfigDTO reviewFileConfigDTO;

    /**
     * 文件上传者
     */
    private final Uploader uploader;

    /**
     * 所有问题反馈截图导出zip(压缩包)
     *
     * @param response http响应
     */
    @Override
    public void exportQuestions(HttpServletResponse response) {
        try {
            // 定义下载文件名称
            String finalFileName = "在线问题反馈截图_"
                    + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".zip";

            // 1. 初始化目录
            File rootPath = this.initExportDirectory();

            // 2. 获取数据
            List<UserQuestionsEntity> entities = this.getQuestionEntities();

            // 3. 创建用户zip文件
            this.createUserZipFiles(entities, rootPath);

            // 4. 创建最终zip文件
            String finalZipPath = Paths.get(rootPath.toString(), finalFileName).toString();
            this.createFinalZip(entities, rootPath, finalZipPath);

            // 5. 设置响应并下载
            this.setDownloadResponse(response, finalZipPath, finalFileName);

            // 6. 清理最终zip文件
            this.cleanUpResources(finalZipPath);
        } catch (BusinessException e) {
            throw e; // 重新抛出已知业务异常
        } catch (Exception e) {
            throw new BusinessException(1006, String.format("导出问题截图过程中发生未知错误: 【%s】", e.getMessage()));
        }
    }

    /**
     * 初始化导出目录
     *
     * @return 文件
     */
    private File initExportDirectory() {
        // 确保父级目录存在
        File rootPath = new File(reviewFileConfigDTO.getQuestionRootPath());

        if (!rootPath.exists() && !rootPath.mkdirs()) {
            throw new BusinessException(1001, String.format("创建目录失败：【%s】", rootPath.getAbsolutePath()));
        }

        return rootPath;
    }

    /**
     * 获取有截图的问题反馈数据
     *
     * @return 数据集
     */
    private List<UserQuestionsEntity> getQuestionEntities() {
        List<UserQuestionsEntity> entities = userQuestionsService.getQuestions();

        if (entities.isEmpty()) {
            throw new BusinessException(1002, "没有找到可导出的问题截图");
        }

        return entities;
    }

    /**
     * 创建用户zip文件（实现第一次压缩）
     *
     * @param entities 数据集
     * @param rootPath 根目录资源
     */
    private void createUserZipFiles(List<UserQuestionsEntity> entities, File rootPath) {
        String parentPath = reviewFileConfigDTO.getQuestionImg();

        for (UserQuestionsEntity entity : entities) {
            String[] paths = entity.getFilePaths().split(",");
            String userZipPath = Paths.get(rootPath.toString(),
                    entity.getCreatorAccountId() + ".zip").toString();

            try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(Paths.get(userZipPath)))) {
                for (String path : paths) {
                    String imagePath = Paths.get(parentPath, path).toString();
                    if (!imagePath.startsWith(parentPath)) {
                        log.warn("警告：非法文件路径尝试: 【{}】", imagePath);
                        continue;
                    }

                    File file = new File(imagePath);

                    if (file.exists()) {
                        uploader.fileToZip(imagePath, zipOut);
                    }
                }
            } catch (IOException e) {
                throw new BusinessException(1003, String.format("创建用户压缩包失败: %s【%s】", userZipPath, e));
            }
        }
    }

    /**
     * 创建最终zip文件（实现二次压缩逻辑）
     *
     * @param entities     数据集
     * @param rootPath     跟目录资源
     * @param finalZipPath 最终zip文件路径
     */
    private void createFinalZip(List<UserQuestionsEntity> entities, File rootPath, String finalZipPath) {
        try (ZipOutputStream finalZipOut = new ZipOutputStream(Files.newOutputStream(Paths.get(finalZipPath)))) {
            for (UserQuestionsEntity entity : entities) {
                String userZipPath = Paths.get(rootPath.toString(),
                        entity.getCreatorAccountId() + ".zip").toString();
                File userZipFile = new File(userZipPath);

                if (!userZipFile.exists()) {
                    continue;
                }

                uploader.fileToZip(userZipPath, finalZipOut);

                // 删除临时用户zip文件
                if (!userZipFile.delete()) {
                    log.warn("警告：删除临时用户压缩包失败，文件可能被占用或不存在: 【{}】", userZipPath);
                }
            }
        } catch (IOException e) {
            throw new BusinessException(1004, String.format("创建最终压缩包失败：【%s】", e));
        }
    }

    /**
     * 设置响应并下载（实现响应设置和下载逻辑）
     *
     * @param response      http响应流
     * @param finalZipPath  最终zip文件路径
     * @param finalFileName zip文件名称
     */
    private void setDownloadResponse(HttpServletResponse response, String finalZipPath, String finalFileName) {
        try {
            String encodedFilename = URLEncoder.encode(finalFileName, StandardCharsets.UTF_8.name());
            response.setHeader("Content-Disposition", "attachment;filename=" + encodedFilename);
        } catch (UnsupportedEncodingException e) {
            // 理论上不会发生，因为UTF-8是必须支持的
            response.setHeader("Content-Disposition", "attachment;filename=feedback_screenshots.zip");
            log.warn("警告: UTF-8编码不支持，使用默认文件名");
        }

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(finalZipPath));
             BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {
            IOUtils.copy(bis, bos);
            response.flushBuffer();
        } catch (IOException e) {
            throw new BusinessException(1005, String.format("文件下载失败：【%s】", e.getMessage()));
        }
    }

    /**
     * 清理最终zip文件
     *
     * @param finalZipPath 最终zip文件路径
     */
    private void cleanUpResources(String finalZipPath) {
        if (!new File(finalZipPath).delete()) {
            log.warn("警告: 删除最终压缩包失败: 【{}】", finalZipPath);
        }
    }
}
